﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Microsoft.Practices.Unity;
using LCA.Community.DAL.Interfaces;
using LCA.Community.Web.Models;
using LCA.Community.DAL.Model;
using LCA.Community.Web.Filters;

namespace LCA.Community.Web.Controllers
{
    /// <summary>
    /// Controller for managing questions
    /// </summary>
    public class QuestionsController : BaseController
    {
        private int pageSize = 10;

        /// <summary>
        /// Action for showing the index of questions
        /// </summary>
        /// <param name="page">The page.</param>
        /// <returns>View showing the list of questions</returns>
        public ActionResult Index(int? page)
        {
            var pageNumber = page ?? 0;
            var questions = QuestionsRepository.GetQuestionsPage(pageNumber, pageSize);
            var questionViewModels = QuestionViewModel.ConvertQuestionsList(questions);

            ViewData["page"] = pageNumber;
            ViewData["more"] = QuestionsRepository.GetQuestionsPage(pageNumber + 1, pageSize).FirstOrDefault() != null;

            return View("Index", questionViewModels);
        }

        /// <summary>
        /// Action for showing the details of a specific question
        /// </summary>
        /// <param name="id">The question ID.</param>
        /// <param name="page">The page.</param>
        /// <returns>View showing the details of the question.</returns>
        [ErrorFilter(typeof(NullReferenceException), "QuestionNotFound",2)]
        public ActionResult Detail(string id)
        {
            var question = QuestionsRepository.Get(id);

            var questionViewModel = MvcApplication.Container.Resolve<QuestionViewModel>(new ParameterOverrides { { "question", question } });

            return View("Detail", questionViewModel);
        }


        /// <summary>
        /// Action for adding a new question
        /// </summary>
        /// <returns>View for adding a new question</returns>
        [SecurityFilter(SecurityRequisites="Registered",ErrorResource="NotLoggedIn")]
        public ActionResult AddQuestion()
        {
            var question = new Question();

            return View("AddQuestion", question);
        }

        /// <summary>
        /// Action for adding a new question
        /// </summary>
        /// <param name="question">The question.</param>
        /// <returns>If the question could be added returns to questions page, otherwise it returns to the view for adding a new question.</returns>
        [ValidateInput(false)]
        [AcceptVerbs(HttpVerbs.Post)]
        [SecurityFilter(SecurityRequisites = "Registered", ErrorResource = "NotLoggedIn")]
        public ActionResult AddQuestion(Question question)
        {
            if(ModelState.IsValid)
            {
                question.RowKey = Guid.NewGuid().ToString();
                question.PartitionKey = UserID;
                question.Author = UserID;
                QuestionsRepository.Add(question);
                return RedirectToAction("Index", "Questions", new { page = 0 });
            }
            else
            {
                return View("AddQuestion", question);
            }
        }

        /// <summary>
        /// Edits the question.
        /// </summary>
        /// <param name="questionID">The question ID.</param>
        /// <returns></returns>
        [SecurityFilter(SecurityRequisites = "Registered", ErrorResource = "NotLoggedIn")]
        [ErrorFilter(typeof(ArgumentException), "NoAuthorized", 1)]
        [ErrorFilter(typeof(NullReferenceException), "QuestionNotFound", 2)]
        public ActionResult EditQuestion(string questionID)
        {
            var question = QuestionsRepository.Get(questionID);
            if (question.Author != UserID)
                throw new ArgumentException("User is not the author of the question");

            return View("EditQuestion", question);
        }

        /// <summary>
        /// Action for editing a question
        /// </summary>
        /// <param name="question">The question.</param>
        /// <returns>If the question could be edited returns to view showing the question, otherwise returns to view for editing question.</returns>
        [ValidateInput(false)]
        [AcceptVerbs(HttpVerbs.Post)]
        [SecurityFilter(SecurityRequisites = "Registered", ErrorResource = "NotLoggedIn")]
        [ErrorFilter(typeof(ArgumentException), "NoAuthorized", 1)]
        [ErrorFilter(typeof(NullReferenceException), "QuestionNotFound", 2)]
        public ActionResult EditQuestion(Question question)
        {
            if(ModelState.IsValid)
            {
                var oldQuestion = QuestionsRepository.Get(question.RowKey);

                if (question.Author != UserID)
                    throw new ArgumentException("User is not the author of the question");

                oldQuestion.Tags = question.Tags;
                oldQuestion.Body = question.Body;

                QuestionsRepository.Update(oldQuestion);

                var questionViewModel = MvcApplication.Container.Resolve<QuestionViewModel>(new ParameterOverrides { { "question", oldQuestion } });

                return View("Detail", questionViewModel);
            }
            else
            {
                return View("EditQuestion", question);
            }
        }

        /// <summary>
        /// Action for removing a question
        /// </summary>
        /// <param name="questionID">The question ID.</param>
        /// <returns>View with index of questions.</returns>
        [SecurityFilter(SecurityRequisites = "Registered", ErrorResource = "NotLoggedIn")]
        [ErrorFilter(typeof(ArgumentException), "NoAuthorized", 1)]
        [ErrorFilter(typeof(NullReferenceException), "QuestionNotFound",2)]
        public ActionResult RemoveQuestion(string questionID)
        {
            var question = QuestionsRepository.Get(questionID);

            if (question.Author != UserID)
                throw new ArgumentException("User is not the author.");

            QuestionsRepository.Delete(questionID);

            return RedirectToAction("Index", "Questions", new { page = 0 });
        }

        /// <summary>
        /// Action for adding an answer
        /// </summary>
        /// <param name="answer">The answer.</param>
        /// <returns>If the answer could be loaded return the list of answers, otherwise it returns the partial view for adding an answer.</returns>
        [ValidateInput(false)]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult AddAnswer(Answer answer)
        {
            if (ModelState.IsValid)
            {
                answer.RowKey = Guid.NewGuid().ToString();
                answer.Author = UserID;
                answer.Body = answer.Body;
                AnswersRepository.Add(answer);

                var answers = AnswersRepository.GetAnswersByQuestion(answer.PartitionKey);
                var answerViewModels = AnswerViewModel.ConvertAnswersList(answers);
                return PartialView("ShowQuestionAnswers", answerViewModels);
            }
            else
            {
                var answers = AnswersRepository.GetAnswersByQuestion(answer.PartitionKey);
                var answerViewModels = AnswerViewModel.ConvertAnswersList(answers);
                return PartialView("ShowQuestionAnswers", answerViewModels);
            }
        }

        /// <summary>
        /// Action for editing an answer.
        /// </summary>
        /// <param name="answer">The answer.</param>
        /// <returns>If the answer could be edited return the list of answers, otherwise it returns the partial view for editing an answer.</returns>
        [ValidateInput(false)]
        [AcceptVerbs(HttpVerbs.Post)]
        [SecurityFilter(SecurityRequisites = "Registered", ErrorResource = "NotLoggedIn")]
        [ErrorFilter(typeof(ArgumentException), "NoAuthorized", 1)]
        [ErrorFilter(typeof(NullReferenceException), "QuestionNotFound", 2)]
        public ActionResult EditAnswer(Answer answer)
        {
            var oldAnswer = AnswersRepository.Get(answer.RowKey);

            if (oldAnswer.Author != UserID)
                throw new ArgumentException("User is not the author of the answer.");

            if (ModelState.IsValid)
            {
                oldAnswer.Body = answer.Body;

                AnswersRepository.Update(oldAnswer);
            }

            return PartialView("ShowQuestionAnswer", oldAnswer);
        }

        /// <summary>
        /// Action for removing and answer
        /// </summary>
        /// <param name="answerID">The answer ID.</param>
        /// <returns>View of the question the answer was linked to.</returns>
        [SecurityFilter(SecurityRequisites = "Registered", ErrorResource = "NotLoggedIn")]
        [ErrorFilter(typeof(ArgumentException), "NoAuthorized", 1)]
        [ErrorFilter(typeof(NullReferenceException), "QuestionNotFound", 2)]
        public ActionResult RemoveAnswer(string answerID)
        {
            var answer = AnswersRepository.Get(answerID);

            if (answer.Author != UserID)
                throw new ArgumentException("User is not the author of the answer.");

            AnswersRepository.Delete(answer);

            return RedirectToAction("Detail", new { id = answer.PartitionKey });
        }

        /// <summary>
        /// Action fo radding a vote to a answer.
        /// </summary>
        /// <param name="answerID">The answer ID.</param>
        /// <returns>Partial view of the votes of the answer.</returns>
        [SecurityFilter(SecurityRequisites = "Registered", ErrorResource = "NotLoggedIn")]
        [ErrorFilter(typeof(NullReferenceException), "AnswerNotFound", 2)]
        public string AddVote(string answerID)
        {
            var answer = AnswersRepository.Get(answerID);
            if (answer == null)
                throw new ArgumentException("The answer provided doesn't exist.");

            if (!AnswerVotesRepository.HasUserVoted(UserID, answerID))
            {
                AnswerVotesRepository.Add(new AnswerVote(answerID, UserID, 1));
            }

            var votes = AnswerVotesRepository.GetAnswerVotesByAnswer(answerID).Count;
            return votes.ToString();
        }

        [Dependency]
        public IQuestionsRepository QuestionsRepository { get; set; }
        [Dependency]
        public IAnswersRepository AnswersRepository { get; set; }
        [Dependency]
        public IAnswersVotesRepository AnswerVotesRepository { get; set; }
    }
}
